package com.dbflow5.adapter.queriable;

import com.dbflow5.adapter.CacheAdapter;
import com.dbflow5.adapter.ModelAdapter;
import com.dbflow5.database.DatabaseWrapper;
import com.dbflow5.database.FlowCursor;
import com.dbflow5.query.cache.ModelCache;

import java.util.ArrayList;

/**
 * Description: Loads a [List] of [T] with [Table.cachingEnabled] true.
 */
public class CacheableListModelLoader<T> extends ListModelLoader<T> {

    protected CacheAdapter<T> cacheAdapter;
    protected ModelAdapter<T> modelAdapter;

    protected ModelCache<T, ?> modelCache;

    public CacheableListModelLoader(Class<T> modelClass, CacheAdapter<T> cacheAdapter){
        super(modelClass);
        this.cacheAdapter = cacheAdapter;
        modelAdapter = getModelAdapter();
        modelCache = cacheAdapter.modelCache;
    }

    protected ModelAdapter<T> getModelAdapter() {
        if(getInstanceAdapter() instanceof ModelAdapter){
            ModelAdapter<T> modelAdapter = (ModelAdapter<T>)getInstanceAdapter();
            if (!modelAdapter.cachingEnabled()) {
                throw new IllegalArgumentException("You cannot call this method for a table that has" +
                        " no caching id. Either use one Primary Key or use the MultiCacheKeyConverter");
            }
            return modelAdapter;
        }
        throw new IllegalArgumentException("A non-Table type was used.");
    }

    @Override
    public ArrayList<T> convertToData(FlowCursor cursor, DatabaseWrapper databaseWrapper) {
        ArrayList<T> data = new ArrayList<>();
        Object[] cacheValues = new Object[cacheAdapter.cachingColumnSize];
        // Ensure that we aren't iterating over this cursor concurrently from different threads
        if (cursor.goToFirstRow()) {
            do {
                Object[] values = cacheAdapter.getCachingColumnValuesFromCursor(cacheValues, cursor);
                T model = ModelCache.addOrReload(modelCache, cacheAdapter.getCachingId(values),
                        cacheAdapter, modelAdapter, cursor, databaseWrapper);
                data.add(model);
            } while (cursor.goToNextRow());
        }
        return data;
    }
}
